using System;
using System.Collections.Generic;
using System.Text;
using Xeml.Document.Contracts;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Mpi.Common.Collections;

namespace Xeml.Document.Ontologies
{
    public class SimpleOboTerm : IOntologyTerm
    {

        public SimpleOboTerm(string termId)
        {
            _termId = termId;
            _supervisedObjects = new List<Term>();
            _readOnlySupervisedObjects = new ReadOnlyCollection<Term>(_supervisedObjects);
            _oboTagValuePairs = new List<KeyValuePair<string, string>>();
        }

        #region IMaterialSupervisor Members

        private TermAttributeCollection _attributes = new TermAttributeCollection();
        public TermAttributeCollection Attributes
        {
            get
            {
                return _attributes;
            }
        }

        private string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }


        private string _nameSpace;
        public string NameSpace
        {
            get { return _nameSpace; }
            set { _nameSpace = value; }
        }

        private string _nameSpaceAlias;
        public string NameSpaceAlias
        {
            get { return _nameSpaceAlias; }
            set { _nameSpaceAlias = value; }
        }

        private string _definition;

        public string Definition
        {
            get { return _definition; }
            set { _definition = value; }
        }

        private List<KeyValuePair<string, string>> _oboTagValuePairs;

        internal List<KeyValuePair<string, string>> OboTagValuePairs
        {
            get { return _oboTagValuePairs; }

        }



        #endregion

        #region ITermSupervisor<Material> Members

        private string _termId;
        public string TermId
        {
            get { return _termId; }
            set { _termId = value; }
        }


        private List<Term> _supervisedObjects;
        private ReadOnlyCollection<Term> _readOnlySupervisedObjects;
        public IEnumerable<Term> SupervisedObjects
        {
            get { return _readOnlySupervisedObjects; }
        }

        public Term EmitDefaultObject(bool supervised)
        {
            Term m = new Term(this.TermId);

            m.Name = this.Name;
            m.NameSpaceAlias = this.NameSpaceAlias;
            m.Annotations.Add(new TaggedAnnotation("def", this.Definition));

            foreach (KeyValuePair<string, string> tag in _oboTagValuePairs)
            {
                m.Annotations.Add(new TaggedAnnotation(tag.Key, tag.Value));
            }

            return m;
            // m.Description = 
        }

        public void Supervise(Term t)
        {
            if (t.TermId == this.TermId)
            {
                if (!_supervisedObjects.Contains(t))
                {
                    _supervisedObjects.Add(t);
                    t.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(t_PropertyChanged);
                }
            }
            else
                throw new ArgumentException("TermId missmatch", "Parameter");
        }

        void t_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            Term m = sender as Term;
            ValidateMaterialProperties(m);
        }

        public void RejectSupervison(Term t)
        {
            if (_supervisedObjects.Contains(t))
            {
                _supervisedObjects.Remove(t);
                t.PropertyChanged -= new PropertyChangedEventHandler(t_PropertyChanged);
            }
        }

        public void ValidateSupervisedProperties()
        {
            foreach (Term m in this._supervisedObjects)
            {
                ValidateMaterialProperties(m);
            }
        }

        private void ValidateMaterialProperties(Term m)
        {
            if (m.Name != this.Name)
                OnValidation(SeverityCode.Error, "The used material term differs from the ontology term.", m);
            if (m.NameSpaceAlias != this.NameSpaceAlias)
                OnValidation(SeverityCode.Error, "The used material namespace differs from the ontology term.", m);
            if (m.Annotations.Contains("def") && m.Annotations.Find("def").Annotation != this.Definition)
                OnValidation(SeverityCode.Error, "The material definiton differs from the ontology term definition.", m);
        }

        public void PushSupervisedProperties()
        {
            foreach (Term m in this._supervisedObjects)
            {
                m.Name = this.Name;
                m.NameSpaceAlias = this.NameSpaceAlias;
                m.Annotations.Clear();
                m.Annotations.Add(new TaggedAnnotation("def", this.Definition));

                foreach (KeyValuePair<string, string> tag in _oboTagValuePairs)
                {
                    m.Annotations.Add(new TaggedAnnotation(tag.Key, tag.Value));
                }
            }
        }

        public event EventHandler<ValidationMessage> Validation;
        protected virtual void OnValidation(SeverityCode sc, string message, object relObject)
        {
            if (Validation != null)
            {
                Validation(this, new ValidationMessage(sc, message, relObject, false));
            }
        }
        #endregion


        private SimpleOboTermCollection _collection;
        public SimpleOboTermCollection Collection
        {
            get
            {
                return _collection;
            }
            set
            {
                if (value != _collection)
                {
                    _collection = value;

                }
            }
        }


        #region IOntologyTerm Members




        private Term _prototype;
        public Term Prototype
        {
            get
            {
                if (_prototype == null)
                    _prototype = EmitDefaultObject(false);
                return _prototype;
            }
        }

        Term IOntologyTerm.EmitDefaultObject(bool supervised)
        {
            return this.EmitDefaultObject(supervised);
        }



        #endregion
    }

    
}
